import axios from "axios";

/*
  封装axios需求：
    1. 复用请求前缀  /dev-api -> 解决不同环境前缀不同问题
    2. 直接得到响应体数据
    3. 携带公共请求参数 token
    4. 发送请求后promise，如果变成成功状态，就是请求成功，如果变成失败状态，就是请求失败或功能失败
    5. 请求失败，自动进行错误提示
*/

// axios.create方法调用返回值是axios实例（axios实例的功能用法和axios本身基本一致）
const request = axios.create({
  // 传入的配置对象就是request的默认配置
  // baseURL: "/dev-api", // 公共请求前缀
  // baseURL: process.env.NODE_ENV.xxx, // webpack脚手架写法
  baseURL: import.meta.env.VITE_APP_MOCK_API, // vite脚手架写法
  timeout: 20000, // 请求超时时间：请求超过这个时间还未得到响应，就会自动中断请求然后报错
});

/*
  所以：将来使用request发送请求
    1. 触发请求拦截器回调函数
    2. 发送请求 -> axios内部封装的，默认看不到
    3. 触发响应拦截器回调函数
    4. 走后面流程，await之后


  源码：
    promise = promise.resolve(config)

    return promise 
      .then(请求拦截器成功回调, 请求拦截器失败回调)  // 1
      .then(dispatchRequest, undefined) // 2
      .then(响应拦截器成功回调, 响应拦截器失败回调) // 3
 
    因为第一个promise是成功状态，所以第一个then方法只会触发第一个回调函数
    因为第一个promise结果值是config，所以第一个then方法得第一个回调函数的参数就是config

    then方法一定返回一个promise，
      如果内部函数报错，或者内部函数返回失败的promise， then方法返回的promise就是失败状态
      否则then方法返回的promise就是成功状态

    因为请求拦截器成功回调没有报错，也没有返回失败的promise，所以最终then方法返回promise就是成功状态
    因为第二then方法，触发成功的回调 -> dispatchRequest 发送请求

    dispatchRequest返回一个promise，看响应状态码，200-299就是成功，否则是失败
*/

// 设置拦截器
// 请求拦截器（发送请求之前触发）
request.interceptors.request.use(
  // 只会触发第一个回调函数
  (config) => {
    // config 发送请求的配置对象（请求方式、请求地址、请求参数、请求头等）

    // 未来携带公共请求参数
    // config.headers.token = 'xxx'

    // 必须返回config，因为第二步发送请求需要使用config的内容来发送请求
    return config;
  }
  // () => {}
);

// 响应拦截器（响应回来第一时间触发）
request.interceptors.response.use(
  // 触发哪个回调函数，看服务器返回的响应状态码status
  // 成功的回调 200-299
  (response) => {
    /*
      response: {
        config, // 请求配置
        headers, // 响应头
        status, // 响应状态码
        request, // xhr
        data,  // 响应体数据 ->
          {
            code: 200,
            data: xxx, // 真正需要的数据
            message: '', // 错误原因
            ok: true
          }
      }
    */

    // 判断请求是否真正成功
    // 200不是固定的值，测试后端接口，看成功返回code的值是多少来定义
    if (response.data.code === 200) {
      // 功能成功
      // return response.data
      return response.data.data;
    } else {
      // ElMessage.error(response.data.message || '请求失败，请联系管理员解决')
      // 功能失败
      return Promise.reject();
    }
  },
  // 失败的回调 非200-299
  (error) => {
    if (error.response) {
      // 服务器返回了响应，响应是失败的
      if (error.status === 401) {
        // unAuthorization token过期
        // 双token刷新机制：发送请求使用refreshToken获取新token
        // 退出登录
        // 将本地存储token删除掉（pinia、localStorage）
        // window.location.href = "/login";
        window.location.reload(); // 刷新（触发全局导航守卫，因为没有token，自动跳转到登录页面）
        return;
      } else if (error.status === 404) {
        // ElMessage.error('访问资源不存在')
      } else if (error.status === 500) {
        // ElMessage.error('请求异常，请稍后重试')
      } else {
        // ElMessage.error('请求失败，请联系管理员解决')
      }
    } else {
      // 服务器没有响应，请求在前端就已经失败了
      if (error.message.indexOf("Network Error")) {
        // 没有网
        // ElMessage.error('网络异常，请尝试重新连接网络')
      } else if (error.message.indexOf("timeout")) {
        // 请求超时
        // ElMessage.error('网络速度慢，请换一个网络试试')
      } else {
        // ElMessage.error('请求失败，请联系管理员解决')
      }
    }

    return Promise.reject();
  }
);

export default request;
